﻿using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Media.Imaging;

namespace Mrkz.ImageManipulation
{
    [Obsolete]
    public class ComplexImage : IEquatable<ComplexImage>
    {
        internal ComplexPixel[,] _data;
        internal int _height;
        internal int _width;
        internal Int32Rect _cropArea;

        double _phase_norm_factor=1.0;
        double _magn_norm_factor=1.0;                      

        internal ComplexImage()
        {
        }       

        public Int32Rect CropArea
        {
            get { return _cropArea; }
        }
        public int Width
        {
            get { return _width; }
        }
        public int Height
        {
            get { return _height; }
        }

        public bool IsValidPixelCoords(int Row, int Col)
        {
            if (Col >= 0
                && Col < Width
                && Row >= 0
                && Row < Height)
                return true;

            return false;
        }             

        public void Normalize()
        {
            double m=0;
            for (int i = 0; i < CropArea.Height; i++)
                for (int j = 0; j < CropArea.Width; j++)
                {
                    if (Math.Log( 1+ _data[i, j].CRed.Magnitude ) > m)
                        m = Math.Log (1+ _data[i, j].CRed.Magnitude);
                    if (Math.Log(1+ _data[i, j].CGreen.Magnitude ) > m)
                        m =Math.Log(1+ _data[i, j].CGreen.Magnitude);
                    if (Math.Log(1+ _data[i, j].CBlue.Magnitude) > m)
                        m =Math.Log(1+ _data[i, j].CBlue.Magnitude );

                }

            _magn_norm_factor = 1/m;
        }
        
        /// <summary>
        /// Write the complex image into two multichannel real images that can be showed
        /// </summary>
        /// <param name="DestinationImage"></param>
        public void WritePixels(WriteableBitmap DestinationImageMagnitude, WriteableBitmap DestinationImagePhase)
        {
            Normalize();

            //create the pixel array for phase plot
            Pixel[,] pixels = new Pixel[Height, Width];
            
            for (int i = 0; i < CropArea.Height; i++)
                for (int j = 0; j < CropArea.Width; j++)
                    pixels[i, j] = new Pixel( Math.Log(1+ _data[i, j].CRed.Phase ) * _phase_norm_factor * 255,
                                               Math.Log(1+ _data[i, j].CGreen.Phase ) * _phase_norm_factor * 255,
                                               Math.Log(1+ _data[i, j].CBlue.Phase ) * _phase_norm_factor  * 255);
            
            GCHandle pinnedPixels = GCHandle.Alloc(pixels, GCHandleType.Pinned);

            int _stride = (_width * 32 + 7) / 8;
         
            DestinationImagePhase.WritePixels(new Int32Rect(0, 0, _width, _height),
                pinnedPixels.AddrOfPinnedObject(),
                _width * _height * 4, _stride);

            pinnedPixels.Free();

            //create the pixel array for magnitude plot
            pixels = new Pixel[Height, Width];

            for (int i = 0; i < CropArea.Height; i++)
                for (int j = 0; j < CropArea.Width; j++)
                    pixels[i, j] = new Pixel( Math.Log(1+ _data[i, j].CRed.Magnitude)* _magn_norm_factor * 255,
                                               Math.Log(1+ _data[i, j].CGreen.Magnitude) * _magn_norm_factor * 255,
                                               Math.Log(1+ _data[i, j].CBlue.Magnitude) * _magn_norm_factor * 255);

            pinnedPixels = GCHandle.Alloc(pixels, GCHandleType.Pinned);            

            DestinationImageMagnitude.WritePixels(new Int32Rect(0, 0, _width, _height),
                pinnedPixels.AddrOfPinnedObject(),
                _width * _height * 4, _stride);

            pinnedPixels.Free();
        
        }

        public void SetPixel(int Row, int Column, ComplexPixel Pixel)
        {           
            _data[Row, Column] = Pixel;
        }

        public void SetPixelWithPad(int Row, int Column, ComplexPixel Pixel)
        {
            if (Row >= Height || Column >= Width)
                return;

            _data[Row, Column] = Pixel;
        }

        public ComplexPixel GetPixel(int Row, int Column)
        {
            return _data[Row, Column];
        }

        public ComplexPixel GetPixelWithPad(int Row, int Column)
        {
            if (Row >= Height || Column >= Width)
                return new ComplexPixel(0, 0, 0);
          
            return _data[Row, Column];
           
        }
        
        public static ComplexImage operator +(ComplexImage A, ComplexImage B)
        {
            if (A.Height != B.Height
                || A.Width != B.Width)
                throw new ArgumentException("Images must be same size");

            ComplexImage res = ComplexImageFactory.CreateEmptyImage(A);

            for (int iR = 0; iR < A.Height; iR++)
                for (int iC = 0; iC < A.Width; iC++)
                    res.SetPixel(iR, iC, A.GetPixel(iR, iC) + B.GetPixel(iR, iC));

            return res;
        }
        public static ComplexImage operator -(ComplexImage A, ComplexImage B)
        {
            if (A.Height != B.Height
                || A.Width != B.Width)
                throw new ArgumentException("Images must be same size");

            ComplexImage res = ComplexImageFactory.CreateEmptyImage(A);

            for (int iR = 0; iR < A.Height; iR++)
                for (int iC = 0; iC < A.Width; iC++)
                    res.SetPixel(iR, iC, A.GetPixel(iR, iC) - B.GetPixel(iR, iC));

            return res;
        }

        public bool Equals(ComplexImage other)
        {             
            if (other.Width == Width 
                && other.Height == Height 
                && other._cropArea.Equals(_cropArea))
            {
                //compare all pixels
                for (int iR = 0; iR < Height; iR++)
                    for (int iC = 0; iC < Width; iC++)
                        if (!_data[iR, iC].Equals(other._data[iR, iC]))
                            return false;

                return true;
            }
            return false;         
        }        
    }
}
